use std::{
    collections::HashSet,
    fs::File,
    io::{BufReader, Error, ErrorKind, Read, Result},
};

#[derive(Clone, Debug, Default)]
struct Item {
    key: String,
    value: Vec<Item>,
}

impl Item {
    fn new(key: String) -> Self {
        Item {
            key,
            value: Vec::new(),
        }
    }
    fn update_keys(&self, set: &mut HashSet<String>) {
        set.insert(self.key.clone());
        for v in &self.value {
            v.update_keys(set);
        }
    }
    fn get_union_count(&self) -> u32 {
        let mut sets = Vec::new();
        for item in &self.value {
            let mut set = HashSet::new();
            item.update_keys(&mut set);
            sets.push(set)
        }
        let mut count = 0;
        while !sets.is_empty() {
            count += 1;
            let mut set = sets[0].clone();
            for s in sets.iter_mut() {
                let intersection: HashSet<_> = set.intersection(s).collect();
                if !intersection.is_empty() {
                    set.extend(s.clone());
                    s.clear();
                }
            }
            sets.retain(|x| !x.is_empty());
        }
        count
    }
}

struct Parser {
    data: Vec<char>,
    pos: usize,
}

fn error<T>(msg: &str) -> Result<T> {
    Err(Error::new(ErrorKind::Other, msg.to_string()))
}

impl Parser {
    fn new(data: String) -> Self {
        Parser {
            data: data.chars().collect(),
            pos: 0,
        }
    }

    fn assert_eq(&mut self, value: char) -> Result<()> {
        self.skip_empty();
        if self.data[self.pos] != value {
            error(&format!("assert_eq {} != {}", self.data[self.pos], value))
        } else {
            self.pos += 1;
            self.skip_empty();
            Ok(())
        }
    }

    fn eof(&self) -> bool {
        self.pos >= self.data.len()
    }

    fn skip_empty(&mut self) {
        while !self.eof() && [' ', '\t', '\r', '\n'].contains(&self.data[self.pos]) {
            self.pos += 1;
        }
    }

    fn parse_string(&mut self, stop_char: char) -> String {
        let mut ret = String::new();
        while self.data[self.pos] != stop_char {
            if self.data[self.pos] == '\\' {
                ret.push(self.data[self.pos + 1]);
                self.pos += 2;
            } else {
                ret.push(self.data[self.pos]);
                self.pos += 1;
            }
        }
        ret
    }

    fn parse_string_list(&mut self) -> Result<Vec<Item>> {
        let mut ret = Vec::new();
        loop {
            self.assert_eq('"')?;
            let item = Item::new(self.parse_string('"'));
            ret.push(item);
            self.assert_eq('"')?;
            self.skip_empty();
            if self.data[self.pos] == ',' {
                self.pos += 1
            } else {
                break;
            }
        }
        Ok(ret)
    }

    fn parse_item_list(&mut self) -> Result<Vec<Item>> {
        let mut ret = Vec::new();
        loop {
            let item = self.parse_item()?;
            ret.push(item);
            self.skip_empty();
            if self.data[self.pos] == ',' {
                self.pos += 1
            } else {
                break;
            }
        }
        Ok(ret)
    }

    fn parse_item(&mut self) -> Result<Item> {
        let mut item = Item::default();

        self.assert_eq('"')?;
        item.key = self.parse_string('"');
        self.assert_eq('"')?;
        self.assert_eq(':')?;
        if self.data[self.pos] == '{' {
            self.pos += 1;
            item.value = self.parse_item_list()?;
            self.assert_eq('}')?;
        } else if self.data[self.pos] == '[' {
            self.pos += 1;
            item.value = self.parse_string_list()?;
            self.assert_eq(']')?;
        } else {
            return error(&format!("format {}", self.data[self.pos]));
        };

        Ok(item)
    }

    fn parse(&mut self) -> Result<Item> {
        let mut item = Item::default();
        self.assert_eq('{')?;
        item.value = self.parse_item_list()?;
        self.assert_eq('}')?;
        Ok(item)
    }
}

fn read(path: &str) -> Result<Item> {
    let file = File::open(path)?;
    let mut reader = BufReader::new(file);
    let mut data = String::new();
    reader.read_to_string(&mut data)?;
    let mut parser = Parser::new(data);
    parser.parse()
}

pub fn count_provinces() -> String {
    let item = read("district.json").unwrap();
    let mut ret = Vec::new();
    for i in item.value {
        ret.push(format!("{}", i.get_union_count()));
    }
    ret.join(",").to_string()
}
